package com.jzm.dispatcher;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.jzm.annotation.AutoWried;
import com.jzm.annotation.PostMapping;
import com.jzm.annotation.ReqeustMapping;
import com.jzm.dto.ClassInfoDTO;
import com.jzm.proxy.DynamicProxy;
import com.jzm.proxy.DynamicServiceProxy;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

/**
 * 总控
 */
/*@WebServlet(name="DispatcherServlet",urlPatterns = "/*",loadOnStartup = 1)*/

@MultipartConfig
public class DispatcherServlet extends HttpServlet {
    // 上传文件存储目录
    private static final String UPLOAD_DIRECTORY = "upload";

    // 上传配置
    private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3;  // 3MB
    private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB
    private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB

    /**
     * 定义一个map容器
     */
    private static Map<String, ClassInfoDTO> map = new HashMap<>();
    /**
     * service实现类对象实例，key：service接口类的全名
     */
    private static Map<String, Object> serviceMap = new HashMap<>();

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        initService();
        initController();
    }

    private static void initService() {
        try {
            //初始化service容器
            //service实现类在哪里
            String serviceImplPath = "com.jzm.service.impl".replaceAll("\\.", "/");
            Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(serviceImplPath);
            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
                String filePath = url.getFile();
                File file = new File(filePath);
                File[] files = file.listFiles();
                //files里面就是controller文件列表
                for (File f : files) {
                    //controller全名（包括完整的包）
                    String serviceImplFullName = "com.jzm.service.impl." + f.getName().split("\\.")[0];
                    //创建class对象，为反射做准备
                    Class<?> aClass = Class.forName(serviceImplFullName);
                    Object instance = aClass.newInstance();
                    Type[] genericInterfaces = aClass.getGenericInterfaces();
                    String key = genericInterfaces[0].getTypeName();
                    DynamicServiceProxy dynamicServiceProxy = new DynamicServiceProxy(instance);
                    serviceMap.put(key, dynamicServiceProxy.getProxy());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化controller容器
     */
    private static void initController() {
        try {
            //扫描controller包下面的类
            String controllerPath = "com.jzm.controller".replaceAll("\\.", "/");
            Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(controllerPath);
            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
                String filePath = url.getFile();
                File file = new File(filePath);
                File[] files = file.listFiles();
                //files里面就是controller文件列表
                for (File f : files) {
                    //controller全名（包括完整的包）
                    String controllerFullName = "com.jzm.controller." + f.getName().split("\\.")[0];
                    //创建class对象，为反射做准备
                    Class<?> aClass = Class.forName(controllerFullName);
                    //Object instance = aClass.newInstance();

                    DynamicProxy dynamicProxy = new DynamicProxy();
                    Object instance = dynamicProxy.getProxy(aClass);

                    //对加了AutoWired注解的成员变量进行实例化
                    Field[] declaredFields = aClass.getDeclaredFields();
                    for (Field field : declaredFields) {
                        AutoWried autoWried = field.getAnnotation(AutoWried.class);
                        if (null != autoWried) {
                            //先拿接口全名
                            String serviceKey = field.getType().getTypeName();
                            Object serivceInstance = serviceMap.get(serviceKey);
                            //更改field的写权限
                            field.setAccessible(true);
                            field.set(instance, serivceInstance);
                        }
                    }


                    //拿类上面的ReqeustMapping注解还有他的值
                    ReqeustMapping reqeustMapping = aClass.getAnnotation(ReqeustMapping.class);
                    String mapKey = reqeustMapping.value();
                    //拿到各个方法里面PostMapping对应的值，还有方法的参数类型
                    Method[] methods = aClass.getMethods();
                    for (Method method : methods) {
                        PostMapping postMapping = method.getAnnotation(PostMapping.class);
                        if (postMapping != null) {
                            ClassInfoDTO classInfoDTO = new ClassInfoDTO();
                            classInfoDTO.setClassInstance(instance);
                            classInfoDTO.setMethod(method);
                            //读取参数类型
                            Class<?>[] parameterTypes = method.getParameterTypes();
                            if (parameterTypes != null && parameterTypes.length > 0) {
                                classInfoDTO.setParamType(parameterTypes[0]);
                            }

                            //放进容器
                            map.put(mapKey + postMapping.value(), classInfoDTO);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String contentType = req.getContentType();
        boolean isFileUpload = contentType != null && contentType.startsWith("multipart/form-data");
        if (isFileUpload) {
            //文件上传
            uploadFile(req, resp);
        } else {
            //普通表单提交
            doNormalFormSubmit(req, resp);
        }
    }

    /**
     * 普通表单提交
     * @param req
     * @param resp
     * @throws IOException
     */
    private static void doNormalFormSubmit(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        //获取提交的json数据
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(req.getInputStream()));
        StringBuilder sb = new StringBuilder(512);
        String line = "";
        while ((line = bufferedReader.readLine()) != null) {
            sb.append(line);
        }
        Object returnObj = null;

        try {
            //sb转成json对象
            JSONObject jsonObject = JSON.parseObject(sb.toString());

            String requestURI = req.getRequestURI();
            //容器里面拿到对应Controller class 信息
            ClassInfoDTO classInfoDTO = map.get(requestURI);

            Method method = classInfoDTO.getMethod();
            //是否包含参数
            Class paramType = classInfoDTO.getParamType();
            if (paramType != null) {
                returnObj = method.invoke(classInfoDTO.getClassInstance(), JSON.parseObject(sb.toString(), paramType));
            } else {
                returnObj = method.invoke(classInfoDTO.getClassInstance());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        PrintWriter writer = resp.getWriter();
        writer.write(JSON.toJSONString(returnObj));
        writer.flush();
        writer.close();
    }

    /**
     * 文件上传
     * @param req
     * @param resp
     * @throws IOException
     * @throws ServletException
     */
    private static void uploadFile(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        //文件上传
        Part file = req.getPart("file");
        String fileName = Paths.get(file.getSubmittedFileName()).getFileName().toString();
        //uuid做为文件名
        String suffix = fileName.substring(fileName.lastIndexOf("\\.") + 1);
        fileName = UUID.randomUUID().toString() + "." + suffix;
        InputStream inputStream = file.getInputStream();
        Path target = Paths.get("D:\\nginx-1.23.3\\html\\static\\" + fileName);
        Files.copy(inputStream, target);
        PrintWriter writer = resp.getWriter();
        //{"filePath":"filePath"}
        writer.write("{\"filePath\":\"" + "http://localhost/static/" + fileName + "\"}");
        writer.flush();
        writer.close();
    }


}
